package com.atguigu.consumer;

import com.atguigu.constant.MqConst;
import com.atguigu.constant.RedisConst;
import com.atguigu.entity.SeckillProduct;
import com.atguigu.entity.UserSeckillSkuInfo;
import com.atguigu.service.SeckillProductService;
import com.atguigu.utils.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Date;
import java.util.List;

@Component
public class SeckillConsumer {
    @Autowired
    private SeckillProductService seckillProductService;
    @Autowired
    private RedisTemplate redisTemplate;
    @RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.SCAN_SECKILL_QUEUE,durable = "false"),
            exchange = @Exchange(value = MqConst.SCAN_SECKILL_EXCHANGE,durable = "false"),
            key = {MqConst.SCAN_SECKILL_ROUTE_KEY}))
    public void scanSeckillProductToRedis(Message message, Channel channel) throws IOException {
        //1.扫描数据库中可秒杀的商品
        QueryWrapper<SeckillProduct> wrapper = new QueryWrapper<>();
        //商品审核状态 1为秒杀商品 2为结束 3审核未通过
        wrapper.eq("status",1);
        //剩余库存数量大于0的
        wrapper.gt("stock_count",0);
        //秒杀的时间是当天的  数据库中将日期进行格式化 具体到年月日即可
        wrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));
        List<SeckillProduct> seckillProductList = seckillProductService.list(wrapper);
        //2.将秒杀的商品放入到redis缓存中
        if (!CollectionUtils.isEmpty(seckillProductList)){
            for (SeckillProduct seckillProduct : seckillProductList) {
                //判断redis中是否有之前的秒杀商品
                Boolean aBoolean = redisTemplate.boundHashOps(RedisConst.SECKILL_PRODUCT).hasKey(seckillProduct.getSkuId().toString());
                if (aBoolean){
                    //如果有已经上架的商品 则跳过
                    continue;
                }else {
                    //没有则往redis中添加
                    redisTemplate.boundHashOps(RedisConst.SECKILL_PRODUCT).put(seckillProduct.getSkuId().toString(),seckillProduct);
                    //再利用list数据结构 将商品的剩余数量储存 让在减库存时候  一个一个的吐出来
                    for (int i = 0; i < seckillProduct.getNum(); i++) {
                        redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX+seckillProduct.getSkuId())
                                .leftPush(seckillProduct.getSkuId().toString());
                    }
                    //3.通知redis集群中的其他节点  该商品可以进行秒杀了
                    //不用mq是因为mq每次只能一个消费者消费信息  而redis可以多个消费者一起消费
                    redisTemplate.convertAndSend(RedisConst.PREPARE_PUB_SUB_SECKILL,seckillProduct.getSkuId()+":"+RedisConst.CAN_SECKILL);
                }
            }
        }
        //确认消息
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }
    //商品预下单的监听器
    @RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.PREPARE_SECKILL_QUEUE,durable = "false"),
            exchange = @Exchange(value = MqConst.PREPARE_SECKILL_EXCHANGE,durable = "false"),
            key = {MqConst.PREPARE_SECKILL_ROUTE_KEY}))
    public void prepareSeckill(UserSeckillSkuInfo userSeckillSkuInfo,Message message, Channel channel) throws IOException{
        if (userSeckillSkuInfo != null){
            //进行处理预下单
            seckillProductService.prepareSeckill(userSeckillSkuInfo);
        }
        //确认消息
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }
    //商品下架的监听器
    @RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.CLEAR_REDIS_QUEUE,durable = "false"),
            exchange = @Exchange(value = MqConst.CLEAR_REDIS_EXCHANGE,durable = "false"),
            key = {MqConst.CLEAR_REDIS_ROUTE_KEY}))
    public void clearRedis(Message message, Channel channel)throws IOException{
        //将结束时间小于等于当前时间的下架
        QueryWrapper<SeckillProduct> wrapper = new QueryWrapper<>();
        wrapper.eq("status",1);
        wrapper.le("end_time",new Date());
        List<SeckillProduct> seckillProductList = seckillProductService.list(wrapper);
        for (SeckillProduct seckillProduct : seckillProductList) {
            //删除redis中商品的库存信息
            redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX+seckillProduct.getSkuId());
            //删除redis中商品的状态信息
            redisTemplate.delete(RedisConst.SECKILL_STATE_PREFIX+seckillProduct.getSkuId());
            //修改DB的商品状态信息
            seckillProduct.setStatus("2");
            seckillProductService.updateById(seckillProduct);
        }
        //删除即将下架的商品信息
        redisTemplate.delete(RedisConst.SECKILL_PRODUCT);
        //删除redis中的预售订单信息
        redisTemplate.delete(RedisConst.PREPARE_SECKILL_USERID_ORDER);
        //删除用户最终抢到的订单信息
        redisTemplate.delete(RedisConst.BOUGHT_SECKILL_USER_ORDER);
        //确认消息
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }
}
